﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;

namespace Mindless
{
    class Program
    {
        public static string Indent(int level)
        {
            return new string(' ', 3 * level);
        }

        static object Choose(string prompt, IList choices)
        {
            Console.WriteLine();
            Console.WriteLine("{0}", prompt);

            int iChoice = 0;
            foreach (object obj in choices)
                Console.WriteLine("{0}: {1}", iChoice++, obj);

            bool isGood = false;
            do
            {
                Console.WriteLine();
                Console.Write("> ");

                string sChoice = Console.ReadLine();

                if (choices.Count == 0)
                    return null;

                try
                {
                    iChoice = int.Parse(sChoice);
                    if (iChoice >= choices.Count)
                        throw new Exception("Try again");
                    isGood = true;
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }

            } while (!isGood);

            return choices[iChoice];
        }

        static void Play(MoveTree tree, MoveTree.Node node)
        {
            while (true)
            {
                Console.WriteLine();
                Console.WriteLine(node.Board);

                if (node.Value == 1)
                {
                    int iWinner = node.WinnerIndex;
                    Play(tree, tree.GetNode(iWinner));
                    return;
                }
                else
                {
                    IList children = new ArrayList();
                    foreach (int iChild in node.GetChildren(tree))
                        children.Add(tree.GetNode(iChild));
                    children.Insert(0, "Undo");
                    object choice = Choose("Move", children);
                    if (choice is MoveTree.Node)
                        Play(tree, (MoveTree.Node) choice);
                    else
                        break;
                }
            }
        }

        static Board BuildBoard(int width, int height, int nPieces)
        {
            Board board = new Board(width, height, Color.Black);
            int nIndexes = ((width * height) + 1) / 2;

            for (int i = 0; i < nPieces; ++i)
            {
                board[i] = new Piece(Color.White, PieceType.Pawn);
                board[nIndexes - i - 1] = new Piece(Color.Black, PieceType.Pawn);
            }

            return board;
        }

        static void Main(string[] args)
        {
            try
            {
                int width = args.Length > 0 ? int.Parse(args[0]) : 5;
                int height = args.Length > 1 ? int.Parse(args[1]) : 5;
                int nPieces = args.Length > 2 ? int.Parse(args[2]) : 3;
                Board board = BuildBoard(width, height, nPieces);
                Console.WriteLine(board);

                MoveTree tree;
                using (new ConsoleTimer("Evaluated"))
                {
                    tree = new MoveTree(board);
                    int result = tree.Evaluate();
                    Console.WriteLine();
                    switch (result)
                    {
                        case 0: Console.WriteLine("Draw"); break;
                        case -1: Console.WriteLine("Second player wins"); break;
                        case 1: Console.WriteLine("First player wins"); break;
                    }
                }

                Play(tree, tree.Root);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                string s = ex.StackTrace;
                if (s.Length > 1000)
                    s = s.Substring(0, 1000);
                Console.WriteLine(s);
            }
        }
    }

    class ConsoleTimer : IDisposable
    {
        public ConsoleTimer(string format, params object[] args)
        {
            this.dtStart = DateTime.Now;
            this.msg = string.Format(format, args);
        }
        DateTime dtStart;
        string msg;

        public void Dispose()
        {
            Console.WriteLine("{0}: {1}", this.msg, DateTime.Now - this.dtStart);
        }
    }
}
